#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
障碍物模块

此模块提供表示环境中各种类型障碍物的类。
"""

import numpy as np
from abc import ABC, abstractmethod


class Obstacle(ABC):
    """
    所有障碍物的抽象基类。
    """
    
    @abstractmethod
    def check_collision(self, x, y, radius=0):
        """
        检查带有可选半径的点 (x, y) 是否与障碍物碰撞。
        
        参数:
            x (float): 点的X坐标
            y (float): 点的Y坐标
            radius (float): 点周围的半径（用于表示机器人）
            
        返回:
            bool: 如果有碰撞则为True，否则为False
        """
        pass
    
    @abstractmethod
    def get_boundaries(self):
        """
        获取障碍物的边界坐标用于可视化。
        
        返回:
            tuple: 用于绘制的 (xs, ys) 坐标数组
        """
        pass


class CircleObstacle(Obstacle):
    """
    表示圆形障碍物的类。
    """
    
    def __init__(self, x, y, radius):
        """
        初始化圆形障碍物。
        
        参数:
            x (float): 中心的X坐标
            y (float): 中心的Y坐标
            radius (float): 圆的半径
        """
        self.x = x
        self.y = y
        self.radius = radius
        self.type = "circle"
    
    def check_collision(self, x, y, radius=0):
        """
        检查带有可选半径的点 (x, y) 是否与圆形障碍物碰撞。
        
        参数:
            x (float): 点的X坐标
            y (float): 点的Y坐标
            radius (float): 点周围的半径（用于表示机器人）
            
        返回:
            bool: 如果有碰撞则为True，否则为False
        """
        # 计算点与圆心之间的距离
        distance = np.sqrt((x - self.x)**2 + (y - self.y)**2)
        
        # 如果距离小于半径之和，则发生碰撞
        return distance < (self.radius + radius)
    
    def get_boundaries(self):
        """
        获取圆形的边界坐标用于可视化。
        
        返回:
            tuple: 用于绘制的 (xs, ys) 坐标数组
        """
        theta = np.linspace(0, 2*np.pi, 100)
        xs = self.x + self.radius * np.cos(theta)
        ys = self.y + self.radius * np.sin(theta)
        return xs, ys


class RectangleObstacle(Obstacle):
    """
    表示矩形障碍物的类。
    """
    
    def __init__(self, x, y, width, height):
        """
        初始化矩形障碍物。
        
        参数:
            x (float): 左下角的X坐标
            y (float): 左下角的Y坐标
            width (float): 矩形的宽度
            height (float): 矩形的高度
        """
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.type = "rectangle"
    
    def check_collision(self, x, y, radius=0):
        """
        检查带有可选半径的点 (x, y) 是否与矩形障碍物碰撞。
        
        参数:
            x (float): 点的X坐标
            y (float): 点的Y坐标
            radius (float): 点周围的半径（用于表示机器人）
            
        返回:
            bool: 如果有碰撞则为True，否则为False
        """
        # 找到矩形上距离给定点最近的点
        closest_x = max(self.x, min(x, self.x + self.width))
        closest_y = max(self.y, min(y, self.y + self.height))
        
        # 计算点与矩形上最近点之间的距离
        distance = np.sqrt((x - closest_x)**2 + (y - closest_y)**2)
        
        # 如果距离小于半径，则发生碰撞
        return distance < radius
    
    def get_boundaries(self):
        """
        获取矩形的边界坐标用于可视化。
        
        返回:
            tuple: 用于绘制的 (xs, ys) 坐标数组
        """
        xs = [self.x, self.x + self.width, self.x + self.width, self.x, self.x]
        ys = [self.y, self.y, self.y + self.height, self.y + self.height, self.y]
        return np.array(xs), np.array(ys)


def create_obstacle_from_config(obstacle_config):
    """
    基于配置创建障碍物的工厂函数。
    
    参数:
        obstacle_config (dict): 障碍物的配置字典
        
    返回:
        Obstacle: 适当障碍物类的实例
    """
    obstacle_type = obstacle_config["type"].lower()
    
    if obstacle_type == "circle":
        return CircleObstacle(
            x=obstacle_config["x"],
            y=obstacle_config["y"],
            radius=obstacle_config["radius"]
        )
    elif obstacle_type == "rectangle":
        return RectangleObstacle(
            x=obstacle_config["x"],
            y=obstacle_config["y"],
            width=obstacle_config["width"],
            height=obstacle_config["height"]
        )
    else:
        raise ValueError(f"Unknown obstacle type: {obstacle_type}") 